package pers.wechat.pay;

import org.dom4j.DocumentException;
import pers.myutil.local.conversion.data.MapConversion;
import pers.myutil.local.random.RandomNumber;
import pers.myutil.local.random.UUID;
import pers.myutil.network.request.NetworkRequest;
import pers.myutil.network.request.RequestMethod;
import pers.myutil.throwable.local.MyUtilLocalException;
import pers.myutil.throwable.network.MyUtilNetworkException;
import pers.wechat.config.WeChatConfig;
import pers.wechat.config.pay.URL;
import pers.wechat.pay.model.AsyncCallBackModel;
import pers.wechat.pay.model.PayModel;
import pers.wechat.pay.throwable.MyWechatPayException;
import pers.wechat.pay.util.WeChatPayUtil;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

public class WeChatPay {

    private WeChatConfig weChatConfig;

    public WeChatPay(WeChatConfig weChatConfig) {
        if(weChatConfig == null){
            weChatConfig = new WeChatConfig();
        }
        this.weChatConfig = weChatConfig;
    }

    /**
     * 生成订单
     * @param body 订单内容
     * @param outTradeNo 订单号
     * @param totalFee 价格
     * @param spbillCreateIp 用户id
     * @param openid 用户openid
     * @return
     * @throws TransformerException
     * @throws ParserConfigurationException
     * @throws MyUtilLocalException
     * @throws MyUtilNetworkException
     * @throws IOException
     * @throws DocumentException
     */
    public PayModel unifiedorder(String body,String outTradeNo,double totalFee,String spbillCreateIp,String openid) throws TransformerException, ParserConfigurationException, MyUtilLocalException, MyUtilNetworkException, IOException, DocumentException, MyWechatPayException {
        SortedMap<String,Object> packageParams = new TreeMap<String,Object>();
//        packageParams.put("appid","wx76efea9cabac61fe");// 程序id
        packageParams.put("appid",weChatConfig.getAppId());// 程序id
//        packageParams.put("mch_id","1524121291");// 商户号
        packageParams.put("mch_id",weChatConfig.getMchId());// 商户号
//        packageParams.put("device_info","");// 设备号
        packageParams.put("nonce_str",String.valueOf(RandomNumber.randomLong(10)));// 随机字符串
//        packageParams.put("sign_type","MD5");// 签名类型
        packageParams.put("body",body);// 商品描述
//        packageParams.put("detail","这是一个测试数据");// 商品详情
        packageParams.put("out_trade_no", outTradeNo);// 订单号
//        packageParams.put("fee_type","CNY");// 币种
        packageParams.put("total_fee",(int)(totalFee*100));// 支付金额
        packageParams.put("spbill_create_ip",spbillCreateIp);
        packageParams.put("notify_url",weChatConfig.getNotifyUrl());
//        packageParams.put("notify_url",weChatConfig.);
        packageParams.put("trade_type","JSAPI");
//        packageParams.put("limit_pay","no_credit");// 限制使用信用卡
        packageParams.put("openid",openid);//用户的openid
//        packageParams.put("sign", WeChatPayUtil.createSign(packageParams,"ddfdd4dbaf814f78b53172520beb53c2"));
        packageParams.put("sign", WeChatPayUtil.createSign(packageParams,weChatConfig.getKey()));

        // 请求获取 prepay_id
        Map<String,Object> requestMap = MapConversion.xmlToMap(NetworkRequest.send(URL.UNIFIEDORDER.getUrl(), RequestMethod.POST,MapConversion.mapToXml(packageParams)));
        System.out.println(requestMap);
        if(!requestMap.get("return_code").equals("SUCCESS")){
//            if(requestMap.get("return_msg").equals("FAIL")){
                throw new MyWechatPayException((String) requestMap.get("return_msg"));
//            }
        }
        if(requestMap.get("result_code").equals("FAIL")){
            if(requestMap.get("err_code").equals("INVALID_REQUEST")){
                throw new MyWechatPayException((String) requestMap.get("err_code_des"));
            }
        }


        SortedMap<String,Object> sortedMap = new TreeMap<>(requestMap);
        if(!requestMap.get("sign").equals(WeChatPayUtil.createSign(sortedMap,weChatConfig.getKey()).toUpperCase())){
            throw new MyWechatPayException("回传签名失败！");
        }

        SortedMap<String,Object> map = new TreeMap<String,Object>();
        map.put("appId",weChatConfig.getAppId());
        map.put("timeStamp",new Date().getTime());
        map.put("nonceStr",UUID.getUUID());
        map.put("package","prepay_id="+requestMap.get("prepay_id"));
        map.put("signType","MD5");
        map.put("paySign",WeChatPayUtil.createSign(map,weChatConfig.getKey()));

        PayModel payModel = new PayModel();
        payModel.setAppId(map.get("appId").toString());
        payModel.setTimeStamp(Long.valueOf(map.get("timeStamp").toString()));
        payModel.setNonceStr(map.get("nonceStr").toString());
//        payModel.setPackages("prepay_id="+prepay_id);
        payModel.setPackages(map.get("package").toString());
        payModel.setSignType("MD5");
        payModel.setPaySign(map.get("paySign").toString());
        return payModel;
    }

    /**
     * 回到哦验证
     * @param request
     * @param response
     * @return
     * @throws IOException
     * @throws DocumentException
     * @throws MyWechatPayException
     */
    public AsyncCallBackModel isWechatSign(HttpServletRequest request,HttpServletResponse response) throws IOException, DocumentException, MyWechatPayException {
        ServletInputStream requestInputStream = request.getInputStream();
        BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(requestInputStream));
        StringBuilder requestData= new StringBuilder();
        String i;
        while (null != (i = bufferedReader.readLine())){
            requestData.append(i);
        }


        SortedMap<String,Object> requestMap = new TreeMap<>(MapConversion.xmlToMap(requestData.toString()));
        if(!requestMap.get("return_code").equals("SUCCESS")){
            throw new MyWechatPayException("回调失败！"+requestMap.get("return_msg"));
        }
        if(!requestMap.get("sign").equals(WeChatPayUtil.createSign(requestMap,weChatConfig.getKey()).toUpperCase())){
            throw new MyWechatPayException("回调签名失败！");
        }

        AsyncCallBackModel asyncCallBackModel = new AsyncCallBackModel();

        asyncCallBackModel.setAppId((String) requestMap.get("appid"));
        asyncCallBackModel.setBankType((String) requestMap.get("bank_type"));
        asyncCallBackModel.setCashFee(String.valueOf(Double.parseDouble(String.valueOf(requestMap.get("cash_fee")))/100));
        asyncCallBackModel.setFeeType((String) requestMap.get("fee_type"));
        asyncCallBackModel.setIsSubscribe((String) requestMap.get("is_subscribe"));
        asyncCallBackModel.setMchId((String) requestMap.get("mch_id"));
        asyncCallBackModel.setNonceStr((String) requestMap.get("nonce_str"));
        asyncCallBackModel.setOpenId((String) requestMap.get("openid"));
        asyncCallBackModel.setOutTradeNo((String) requestMap.get("out_trade_no"));
        asyncCallBackModel.setResultCode((String) requestMap.get("result_code"));
        asyncCallBackModel.setReturnCode((String) requestMap.get("return_code"));
        asyncCallBackModel.setSign((String) requestMap.get("sign"));
        asyncCallBackModel.setTimeEnd((String) requestMap.get("time_end"));
        asyncCallBackModel.setTotalFee((String) requestMap.get("total_fee"));
        asyncCallBackModel.setTradeType((String) requestMap.get("trade_type"));
        asyncCallBackModel.setTransactionId((String) requestMap.get("transaction_id"));

        OutputStream outputStream = response.getOutputStream();
        response.setHeader("content-type", "text/html;charset=UTF-8");
        byte[] dataByteArr = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>".getBytes(StandardCharsets.UTF_8);
        outputStream.write(dataByteArr);
        return asyncCallBackModel;
    }

    public static void main(String[] args) throws TransformerException, ParserConfigurationException, MyUtilLocalException, MyUtilNetworkException, IOException, DocumentException, MyWechatPayException {
        WeChatConfig weChatConfig = new WeChatConfig.Builder()
                .addAppId("wx76efea9cabac61fe")
                .addKey("ddfdd4dbaf814f78b53172520beb53c2")
                .addMchId("1524121291")
                .addNotifyUrl("http://www.baidu.com/index.html")
//                .addKey("ddfdd4dbaf814f78b53172520beb53c2")
                .build();
//                .addAppSecret("1524121291")
        WeChatPay weChatPay = new WeChatPay(weChatConfig);
        System.out.println(weChatPay.unifiedorder("测试",UUID.getUUID(),100,"192.138.1.1","oUnFJ5CO3Dad8KyqrLGoaGIe2Dx4"));
    }

//    public static void main(String[] args) {
////        {nonce_str=GhfA2rW27Tc0y0Ri, appid=wx76efea9cabac61fe, sign=A4CCC19BC3F2E7A3D4BDED05E6D43F5A, trade_type=JSAPI, return_msg=OK, result_code=SUCCESS, mch_id=1524121291, return_code=SUCCESS, prepay_id=wx222143028183447b5efbe34c0635011362}
//        SortedMap<String,Object> map = new TreeMap<String,Object>();
//        map.put("nonce_str","GhfA2rW27Tc0y0Ri");
//        map.put("appid","wx76efea9cabac61fe");
//        map.put("trade_type","JSAPI");
//        map.put("return_msg","OK");
//        map.put("result_code","SUCCESS");
//        map.put("mch_id","1524121291");
//        map.put("prepay_id","wx222143028183447b5efbe34c0635011362");
//        System.out.println(WeChatPayUtil.createSign(map,"ddfdd4dbaf814f78b53172520beb53c2"));
//    }

//    public static void main(String[] args) throws DocumentException {
//        SortedMap<String,Object> map = new TreeMap<>(MapConversion.xmlToMap("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg><appid><![CDATA[wx76efea9cabac61fe]]></appid><mch_id><![CDATA[1524121291]]></mch_id><nonce_str><![CDATA[DJRzt5gpkB1fCHjt]]></nonce_str><sign><![CDATA[40CB8422E0D35B3DCEFF173068687F9C]]></sign><result_code><![CDATA[SUCCESS]]></result_code><prepay_id><![CDATA[wx23110029764520567c1971652853536486]]></prepay_id><trade_type><![CDATA[JSAPI]]></trade_type></xml>"));
//        System.out.println(WeChatPayUtil.createSign(map,"ddfdd4dbaf814f78b53172520beb53c2"));
//    }
}
